/*
 * Stok3d - getting you stoked on Flash Player native 3D
 * Copyright (C) 2009  David Lenaerts
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author information:
 * David Lenaerts
 * url: http://www.derschmale.com
 * mail: david.lenaerts@gmail.com
 * 
 */

package com.derschmale.stok3d.filters
{
	import flash.display.DisplayObject;
	import flash.display.Shader;
	import flash.display.Stage;
	import flash.filters.ShaderFilter;
	import flash.geom.Rectangle;
	import flash.geom.Vector3D;
	
	/**
	 * PixelShader3D is an abstract class used for shaders acting on 3D DisplayObjects.
	 * The shaders passed to the constructor need the following parameters:
	 * <ul>
	 * <li>float4x4 transformation: The 3D transformation matrix of the object</li>
	 * <li>normal: The surface normal of the plane</li>
	 * <li>upperLeft: The upper left coordinate of the displayObject's bounds (in local coordinates)</li>
	 * </ul>
	 */
	public class PixelShader3D extends ShaderFilter implements IFilter3D
	{
		private var _view : Vector3D = new Vector3D();
		
		public function PixelShader3D(shader:Shader=null)
		{
			super(shader);
		}
		
		/**
		 * Updates the filter according to the target's matrix3D.
		 * This function needs to be called whenever the target displayObject changes position, rotation or scale.
		 * 
		 * @param target The DisplayObject for which the shader needs to be updated.
		 */
		public function update(target : DisplayObject) : void
		{
			var bounds : Rectangle = target.getBounds(target);
			var stage : Stage = target.stage;
			var transform : Vector.<Number> =  target.transform.matrix3D.rawData;
			
			shader.data.upperLeft.value = [ bounds.x, bounds.y ];
			
			shader.data.transformation.value = [ 	transform[0], transform[1], transform[2], transform[3], 
													transform[4], transform[5], transform[6], transform[7], 
													transform[8], transform[9], transform[10], transform[11], 
													transform[12]-stage.stageWidth*.5, transform[13]-stage.stageHeight*.5, transform[14], transform[15]
												];
			_view.x = target.x-stage.stageWidth*.5;
			_view.y = target.y-stage.stageHeight*.5;
			_view.z = target.z;
			_view.normalize();
			if (_view.x*transform[8]+_view.y*transform[9]+_view.z*transform[10] > 0)
				shader.data.normal.value = [ -transform[8], -transform[9], -transform[10] ];
			else
				shader.data.normal.value = [ transform[8], transform[9], transform[10] ];
		}
	}
}